#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
@Author          : ricsy
@File            : scss_compiler.py
@Create Time     : 2025/6/9 21:11
@Last Modified   :
@Description     :
"""
import os
import subprocess
from pathlib import Path
from typing import Literal

import sass

from src.settings import logger
from utils.config_processor import ConfigProcessor
from utils.environment_check import EnvironmentChecker


config = ConfigProcessor()
static_dir = config.get_static_dir()
build_config = config.as_namespace("build")
source_dir, files_to_compile = build_config.source_dir, build_config.compile_scss or [
    "main.scss"
]

scss_dir = static_dir / "assets/scss"
css_dir = static_dir / "assets/css"


class SCSSCompiler:
    def __init__(
        self,
        compiler_type: Literal["dartsass", "libsass"],
        debug=False,
    ):
        """
        :param debug: 是否调试模式，True 时不压缩输出
        :param compiler_type: 编译器类型，可选 'libsass' 或 'dartsass'
        """
        self.debug = debug
        self.compiler_type = compiler_type
        # 自动查找 dart-sass 可执行文件
        self.sass_cmd = EnvironmentChecker().get_executable_path("sass")
        logger.info(f"[SCSS] sass 执行路径: {self.sass_cmd}", 2)
        logger.info(f"[SCSS] 编译器: {self.compiler_type}", 1)

    def compile_scss(
        self,
    ) -> None:
        """
        编译 SCSS 文件，支持选择编译器类型
        """
        # Nested（嵌套格式）：反映 SCSS 的嵌套结构，适合开发调试
        # Expanded（展开格式）：类似手写CSS的经典格式，可读性最佳，选择器和声明独占一行，缩进清晰，媒体查询等复杂结构更易读
        # Compact（紧凑格式）：平衡可读性和文件大小，每个规则集单行显示，声明写在同一行，保留必要的空格
        # Compressed（压缩格式）：极致压缩，适合生产环境，删除所有注释和空白符，简化颜色值，移除分号等非必要符号
        output_style: Literal["nested", "expanded", "compact", "compressed"] = (
            "expanded" if self.debug else "compressed"
        )

        try:
            os.makedirs(scss_dir, exist_ok=True)
            os.makedirs(css_dir, exist_ok=True)

            # 编译所有 SCSS 文件
            for scss_file in files_to_compile:
                scss_config = []
                if isinstance(scss_file, dict):
                    for key, value in scss_file.items():
                        if not key.endswith(".scss"):
                            key += ".scss"
                        if not value.endswith(".css"):
                            value += ".css"
                        scss_config.append({"source": key, "target": value})
                elif isinstance(scss_file, str):
                    if not scss_file.endswith(".scss"):
                        scss_file += ".scss"
                    scss_file_name = os.path.splitext(os.path.basename(scss_file))[0]
                    scss_config.append(
                        {
                            "source": scss_file,
                            "target": f"{scss_file_name}.css",
                        }
                    )
                for item in scss_config:
                    source, target = item["source"], item["target"]
                    scss_path = Path(scss_dir / source).resolve()
                    css_path = Path(css_dir / target).resolve()
                    if self.compiler_type == "dartsass":
                        self._compile_with_dartsass(
                            scss_path=scss_path,
                            css_path=css_path,
                            output_style=output_style,
                        )
                    else:
                        self._compile_with_libsass(
                            scss_path=scss_path,
                            css_path=css_path,
                            output_style=output_style,
                        )
        except Exception as e:
            logger.error(f"[SCSS] {e}", exc_info=self.debug)

    def _compile_with_libsass(
        self,
        scss_path: Path,
        css_path: Path,
        output_style: Literal["nested", "expanded", "compact", "compressed"],
    ) -> None:
        """使用 libsass 编译"""
        css = sass.compile(
            filename=str(scss_path),
            output_style=output_style,
            source_comments=self.debug,  # 调试模式下添加源映射注释
            omit_source_map_url=not self.debug,  # 调试模式下不输出源映射 URL
        )
        with open(css_path, "w", encoding="utf-8") as f:
            f.write(css)
        logger.info(f"[SCSS] 生成文件：{css_path}", 2)

    def _compile_with_dartsass(
        self,
        scss_path: Path,
        css_path: Path,
        output_style: str,
    ) -> None:
        """使用本地 dart-sass 命令编译"""
        _args = [
            str(self.sass_cmd),
            f"--style={output_style}",
            "--no-error-css",  # 禁用错误CSS生成
            str(scss_path),
            str(css_path),
        ]

        if self.debug:
            _args.extend(
                [
                    "--embed-sources",  # 嵌入源码到sourcemap
                    "--source-map",  # 生成sourcemap
                ]
            )

        try:
            subprocess.run(
                _args, check=True, capture_output=True, text=True, encoding="utf-8"
            )
            logger.info(f"[SCSS] 生成文件：{css_path}", 2)
        except subprocess.CalledProcessError as e:
            raise RuntimeError(
                f"DartSass 编译失败: {e.stderr or '未知错误'}\n"
                f"命令: {' '.join(_args)}"
            ) from e


if __name__ == "__main__":
    import argparse

    parser = argparse.ArgumentParser(description="SCSS 编译工具")
    parser.add_argument("--debug", action="store_true", help="启用调试模式")
    parser.add_argument(
        "--type",
        choices=["libsass", "dartsass"],
        default="dartsass",
        help="选择编译器类型（默认: dartsass）",
    )
    args = parser.parse_args()

    scss_compiler = SCSSCompiler(
        debug=args.debug,
        compiler_type=args.type,
    )

    scss_compiler.compile_scss()
